﻿//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Expenses.ViewModels;
using Expenses.ExpenseService;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using Windows.UI.Popups;
using Windows.UI.StartScreen;
using Expenses.Controls;
using Windows.ApplicationModel.DataTransfer;
using System.Text;
using Callisto.Controls;
using Windows.UI;

namespace Expenses.Views
{
    public sealed partial class ExpenseReportPage : Expenses.Common.LayoutAwarePage
    {
        ObservableCollection<ExpenseItemViewModel> expenseItems = null;
        ExpenseItemsViewModel expenseItemsViewModel = null;
        ExpenseReportViewModel expenseReport = null;
        ExpenseReportViewModel expenseReportViewModel = null;
        DataTransferManager dataTransferManager = null;

        public ExpenseReportPage()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            expenseReportViewModel = new ExpenseReportViewModel();
            expenseReport = new ExpenseReportViewModel();
            expenseItemsViewModel = new ExpenseItemsViewModel();

            if (App.CurrentExpenseReport == null)
            {
                InitializeExpenseReport();
                InitializeExpenseItems();
                PageTitleTextBlock.Text = "This report has not been saved";
            }
            else
            {
                int selectedReportNumber =
                    App.CurrentExpenseReport.ReportNumber;

                GetExpenseReport(selectedReportNumber);

                // If not pinned, show pin button. If pinned, show unpin button.
                if (Windows.UI.StartScreen.SecondaryTile.Exists(
                    (selectedReportNumber).ToString()))
                {
                    PinReportButton.Visibility = Visibility.Collapsed;
                    UnpinReportButton.Visibility = Visibility.Visible;
                }
                else
                {
                    PinReportButton.Visibility = Visibility.Visible;
                    UnpinReportButton.Visibility = Visibility.Collapsed;
                }
            }
            // Register handler for DataRequested events for sharing
            dataTransferManager = DataTransferManager.GetForCurrentView();
            dataTransferManager.DataRequested += new TypedEventHandler<
                DataTransferManager, DataRequestedEventArgs>(OnDataRequested);
        }

        private void InitializeExpenseReport()
        {
            PurposeTextBox.Visibility = Visibility.Visible;
            ApproverTextBox.Visibility = Visibility.Visible;
            CostCenterTextBox.Visibility = Visibility.Visible;
            NotesTextBox.Visibility = Visibility.Visible;
            DiscardReportButton.Visibility = Visibility.Collapsed;
            PinReportButton.Visibility = Visibility.Collapsed;

            ExpenseReportGrid.DataContext = expenseReport;
            App.CurrentExpenseReport = expenseReport;
        }

        private void InitializeExpenseItems()
        {
            expenseItems = new ObservableCollection<ExpenseItemViewModel>();
            AddExpenseItems();
            App.CurrentExpenseItems = expenseItems;

            ExpenseItemsViewSource.Source = expenseItems;

            CalculateOwedToAmounts();
            DisplayExpenseItemsSummary();
        }

        private async void GetExpenseReport(int reportNumber)
        {
            ExpenseReportProgressRing.IsActive = true;

            expenseReport = await expenseReportViewModel.GetExpenseReport(reportNumber);
            ExpenseReportGrid.DataContext = expenseReport;
            App.CurrentExpenseReport = expenseReport;

            string pageTitle = string.Empty;
            if (!App.IsManager)
            {
                pageTitle = string.Format("Report {0}", expenseReport.ReportNumber);
            }
            else
            {
                pageTitle = string.Format("Report {0} from {1}",
                    expenseReport.ReportNumber, expenseReport.EmployeeName);
            }
            if (expenseReport.Status == StatusType.Saved)
            {
                pageTitle += string.Format("  (saved on {0:d})", expenseReport.DateSaved);

                PurposeTextBox.Visibility = Visibility.Visible;
                ApproverTextBox.Visibility = Visibility.Visible;
                CostCenterTextBox.Visibility = Visibility.Visible;
                NotesTextBox.Visibility = Visibility.Visible;
            }
            else
            {
                ExpenseItemsGridView.SelectionMode = (ListViewSelectionMode)SelectionMode.Single;
                ExpenseItemsGridView.IsSwipeEnabled = false;
                if (expenseReport.Status == StatusType.Pending)
                {
                    pageTitle += string.Format("  (submitted on {0:d})", 
                        expenseReport.DateSubmitted);
                }
                else
                {
                    pageTitle += string.Format("  (submitted on {0:d}, approved on {1:d})", 
                        expenseReport.DateSubmitted, expenseReport.DateResolved);
                }

                PurposeTextBlock.Visibility = Visibility.Visible;
                ApproverTextBlock.Visibility = Visibility.Visible;
                CostCenterTextBlock.Visibility = Visibility.Visible;
                NotesTextBlock.Visibility = Visibility.Visible;

                AddChargeButton.Visibility = Visibility.Collapsed;
                SaveReportButton.Visibility = Visibility.Collapsed;
                DiscardReportButton.Visibility = Visibility.Collapsed;

                if (App.IsManager)
                {
                    ApproveReportButton.Visibility = Visibility.Visible;
                    RejectReportButton.Visibility = Visibility.Visible;
                }
            }
            PageTitleTextBlock.Text = pageTitle;

            if (App.SelectedCharges != null)
            {
                expenseReport.IsDirty = true;
            }
            else
            {
                expenseReport.IsDirty = false;
            }

            // Now get the expense items for this report
            expenseItems = await expenseItemsViewModel.GetExpenseItems(reportNumber);
            ExpenseItemsViewSource.Source = expenseItems;
            AddExpenseItems();
            App.CurrentExpenseItems = expenseItems;

            DisplayExpenseItemsSummary();
            CalculateOwedToAmounts();

            ExpenseReportProgressRing.IsActive = false;
        }

        private void AddExpenseItems()
        {
            if (App.SelectedCharges != null)
            {
                foreach (ChargeViewModel charge in 
                    App.SelectedCharges)
                {
                    expenseItems.Add(
                        new ExpenseItemViewModel
                        {
                            ExpenseDate = charge.ExpenseDate,
                            EmployeeId = charge.EmployeeId,
                            Merchant = charge.Merchant,
                            Location = charge.Location,
                            BilledAmount = charge.BilledAmount,
                            TransactionAmount = charge.TransactionAmount,
                            Description = charge.Description,
                            Category = charge.Category,
                            AccountNumber = charge.AccountNumber,
                            ReceiptRequired = charge.ReceiptRequired,
                            ExpenseType = charge.ExpenseType,
                            Notes = charge.Notes,
                            ChargeId = charge.Id
                        }
                        );
                }
            }
        }

        private void CalculateOwedToAmounts()
        {
            var owedToCreditCard =
                (from item in expenseItems
                 where item.ExpenseType == 1
                 select item.BilledAmount).Sum();
            expenseReport.OwedToCreditCard = owedToCreditCard;
            OwedToCreditCardTextBlock.Text = string.Format(
                "{0:C}", expenseReport.OwedToCreditCard);

            var owedToEmployee =
                (from item in expenseItems
                 where item.ExpenseType == 2
                 select item.BilledAmount).Sum();
            expenseReport.OwedToEmployee = owedToEmployee;
            OwedToEmployeeTextBlock.Text = string.Format(
                "{0:C}", expenseReport.OwedToEmployee);

        }

        private void DisplayExpenseItemsSummary()
        {
            int numberOfExpenseItems = (from item in expenseItems
                                        select item).Count();
            decimal amountOfExpenseItems = (from item in expenseItems
                                            select item.BilledAmount).Sum();
            if (numberOfExpenseItems == 0)
            {
                ExpenseItemsSummaryTextBlock.Text = "No items in report";
            }
            else
            {
                ExpenseItemsSummaryTextBlock.Text = string.Format(
                    "{0} item(s) for {1:C}",
                    numberOfExpenseItems, amountOfExpenseItems);
                ExpenseItemsErrorTextBlock.Visibility = Visibility.Collapsed;
            }
        }

        private async void AddChargeButton_Click(object sender, RoutedEventArgs e)
        {
            if (expenseReport.ReportNumber == 0)
            {
                ShowFlyout("Save the expense report first.", "AddChargeButton");
                return;
            }
            if (expenseReport.IsDirty == true)
            {
                var menu = new PopupMenu();
                menu.Commands.Add(new UICommand("Save", (command) =>
                {
                    SaveExpenseReport(false);
                }));
                menu.Commands.Add(new UICommand("Discard", (command) =>
                {
                    // Nothing to do if no saving
                }));
                var chosenCommand = await menu.ShowForSelectionAsync(
                    GetElementRect((FrameworkElement)sender), Placement.Above);
            }
            this.Frame.Navigate(typeof(ChargesPage));
        }

        private async void SaveReportButton_Click(object sender, RoutedEventArgs e)
        {
            // Validate the report
            if (expenseReport.Purpose == string.Empty)
            {
                PurposeErrorTextBlock.Visibility = Visibility.Visible;
                return;
            }
            if (expenseItems.Count() == 0)
            {
                ExpenseItemsErrorTextBlock.Visibility = Visibility.Visible;
                return;
            }
            if (expenseReport.Approver == string.Empty)
            {
                ApproverErrorTextBlock.Visibility = Visibility.Visible;
                return;
            }
            if (CostCenterTextBox.Text == string.Empty)
            {
                CostCenterErrorTextBlock.Visibility = Visibility.Visible;
                return;
            }

            var menu = new PopupMenu();
            menu.Commands.Add(new UICommand("Submit report", (command) =>
            {
                SaveExpenseReport(true);
            }));
            menu.Commands.Add(new UICommand("Do not submit report", (command) =>
            {
                SaveExpenseReport(false);
            }));
            var chosenCommand = await menu.ShowForSelectionAsync(
                GetElementRect((FrameworkElement)sender), Placement.Above);
        }

        private async void SaveExpenseReport(bool submit)
        {
            string result = await expenseReport.SaveExpenseReport(
                expenseReport, expenseItems.ToList(), submit);

            if (result.Contains("Success"))
            {
                expenseReport.IsDirty = false;
                ClearAppLevelProperties();
                this.Frame.Navigate(typeof(ExpenseReportsPage), "Saved Reports");
            }
            else
            {
                ShowFlyout(result, "SaveReportButton");
            }
        }

        private async void DiscardReportButton_Click(object sender, RoutedEventArgs e)
        {
            string result = await expenseReportViewModel.DeleteExpenseReport(
                expenseReport.ReportNumber);

            if (result.Contains("Success"))
            {
                ClearAppLevelProperties();
                this.Frame.Navigate(typeof(ExpenseReportsPage), "Saved Reports");
            }
            else
            {
                ShowFlyout(result, "DiscardReportButton");
            }
        }

        private void RemoveChargeButton_Click(object sender, RoutedEventArgs e)
        {
            string selection = string.Empty;
            foreach (ExpenseItemViewModel item in ExpenseItemsGridView.SelectedItems)
            {
                expenseItems.Remove(item);
            }
            expenseReport.IsDirty = true;

            HideRemoveChargeButton();
            ExpenseReportAppBar.IsOpen = false;
            DisplayExpenseItemsSummary();
        }

        private void ExpenseItemsGridView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (expenseReport.Status != StatusType.Saved)
            {
                return;
            }
            if (ExpenseItemsGridView.SelectedItems.Count() > 0)
            {
                ExpenseReportAppBar.IsOpen = true;
                ExpenseReportAppBar.IsSticky = true;
                RemoveChargeButton.Visibility = Visibility.Visible;
            }
            else
            {
                ExpenseReportAppBar.IsOpen = false;
                ExpenseReportAppBar.IsSticky = false;
                RemoveChargeButton.Visibility = Visibility.Collapsed;
            }
        }

        private void ExpenseItemsGridView_ItemClick(object sender, ItemClickEventArgs e)
        {
            if (expenseReport.ReportNumber == 0)
            {
                ShowFlyout("Save the expense report first.", "ExpenseItemsGridView");
                return;
            }
            this.Frame.Navigate(typeof(ExpenseItemPage), e.ClickedItem);
        }

        private void PurposeTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            if (PurposeTextBox.Text != string.Empty)
            {
                PurposeErrorTextBlock.Visibility = Visibility.Collapsed;
            }
        }

        private void ApproverTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            if (ApproverTextBox.Text != string.Empty)
            {
                ApproverErrorTextBlock.Visibility = Visibility.Collapsed;
            }
        }

        private void CostCenterTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            if (CostCenterTextBox.Text != string.Empty)
            {
                CostCenterErrorTextBlock.Visibility = Visibility.Collapsed;
            }
        }

        private void ShowRemoveChargeButton()
        {
            RemoveChargeButton.Visibility = Visibility.Visible;
        }

        private void HideRemoveChargeButton()
        {
            RemoveChargeButton.Visibility = Visibility.Collapsed;
        }

        private async void BackButton_Click(object sender, RoutedEventArgs e)
        {
            if (expenseReport.IsDirty == true)
            {
                var messageDialog = new MessageDialog(
                    "Do you want to save your changes?", "You made changes");
                messageDialog.Commands.Add(new UICommand("Save", (command) =>
                {
                    SaveExpenseReport(false);
                }));
                messageDialog.Commands.Add(new UICommand("Don't save", (command) =>
                {
                }));
                messageDialog.DefaultCommandIndex = 1;
                await messageDialog.ShowAsync();
            }
            ClearAppLevelProperties();
            GoBack();
        }

        private void GoBack()
        {
            switch (App.LastPage)
            {
                case "Saved Reports":
                    this.Frame.Navigate(typeof(ExpenseReportsPage), "Saved Reports");
                    break;
                case "Pending Reports":
                    this.Frame.Navigate(typeof(ExpenseReportsPage), "Pending Reports");
                    break;
                case "Needing Approval":
                    this.Frame.Navigate(typeof(ExpenseReportsPage), "Needing Approval");
                    break;
                case "ExpenseReportsHistoryPage":
                    this.Frame.Navigate(typeof(ExpenseReportsHistoryPage));
                    break;
                default:
                    this.Frame.Navigate(typeof(MainPage));
                    break;
            }
        }

        private async void ApproveReportButton_Click(object sender, RoutedEventArgs e)
        {
            string result = await expenseReport.ApproveExpenseReport(expenseReport.ReportNumber);

            if (result.Contains("Success"))
            {
                expenseReport.IsDirty = false;
                ClearAppLevelProperties();
                this.Frame.Navigate(typeof(ExpenseReportsPage), "Needing Approval");
            }
            else
            {
                ShowFlyout(result, "ApproveReportButton");
            }
        }

        private async void RejectReportButton_Click(object sender, RoutedEventArgs e)
        {
            string result = await expenseReport.RejectExpenseReport(expenseReport.ReportNumber);

            if (result.Contains("Success"))
            {
                expenseReport.IsDirty = false;
                ClearAppLevelProperties();
                this.Frame.Navigate(typeof(ExpenseReportsPage), "Needing Approval");
            }
            else
            {
                ShowFlyout(result, "ApproveReportButton");
            }
        }

        private async void ShowMessage(string message)
        {
            var dlg = new Windows.UI.Popups.MessageDialog(message);
            dlg.Commands.Add(new Windows.UI.Popups.UICommand("OK", null, "OK"));
            await dlg.ShowAsync();
        }

        private void ShowFlyout(string message, string control)
        {
            var flyout = new Flyout();
            flyout.Content = new TextBlock()
            {
                Text = message,
                Foreground = new SolidColorBrush(Colors.Black),
                Margin = new Thickness(10, 0, 10, 0),
                VerticalAlignment = VerticalAlignment.Center,
                FontSize = 18
            };
            flyout.Placement = PlacementMode.Top;
            switch (control)
            {
                case "ExpenseItemsGridView":
                    flyout.PlacementTarget = ExpenseItemsGridView;
                    break;
                case "AddChargeButton":
                    flyout.PlacementTarget = AddChargeButton;
                    break;
                case "SaveReportButton":
                    flyout.PlacementTarget = SaveReportButton;
                    break;
                case "DiscardReportButton":
                    flyout.PlacementTarget = DiscardReportButton;
                    break;
                case "ApproveReportButton":
                    flyout.PlacementTarget = ApproveReportButton;
                    break;
                case "RejectReportButton":
                    flyout.PlacementTarget = RejectReportButton;
                    break;
                default:
                    flyout.PlacementTarget = ExpenseItemsGridView;
                    break;
            }
            flyout.IsOpen = true;
        }

        public static Rect GetElementRect(FrameworkElement element)
        {
            GeneralTransform buttonTransform = element.TransformToVisual(null);
            Point point = buttonTransform.TransformPoint(new Point());
            return new Rect(point, new Size(element.ActualWidth, element.ActualHeight));
        }

        private async void PinReportButton_Click(object sender, RoutedEventArgs e)
        {
            string tileActivationArguments = string.Format(
                "Saved:{0}", expenseReport.ReportNumber);
            var secondaryTile = new SecondaryTile(
                expenseReport.ReportNumber.ToString(),
                expenseReport.Purpose,
                expenseReport.Purpose,
                tileActivationArguments,
                TileOptions.ShowNameOnLogo,
                new Uri("ms-appx:///Assets/MyExpensesLogo.png"));

            bool isPinned = await secondaryTile.RequestCreateForSelectionAsync(
                GetElementRect((FrameworkElement)sender),
                Windows.UI.Popups.Placement.Below);

            if (isPinned == true)
            {
                UnpinReportButton.Visibility = Visibility.Visible;
                PinReportButton.Visibility = Visibility.Collapsed;
            }
        }

        private async void UnpinReportButton_Click(object sender, RoutedEventArgs e)
        {
            if (Windows.UI.StartScreen.SecondaryTile.Exists(
                expenseReport.ReportNumber.ToString()))
            {
                // First prepare the tile to be unpinned
                var secondaryTile = new SecondaryTile(
                    expenseReport.ReportNumber.ToString());
                // Now make the delete request.
                bool isUnpinned = await secondaryTile.RequestDeleteForSelectionAsync(
                    GetElementRect((FrameworkElement)sender),
                    Windows.UI.Popups.Placement.Below);

                if (isUnpinned == true)
                {
                    UnpinReportButton.Visibility = Visibility.Collapsed;
                    PinReportButton.Visibility = Visibility.Visible;
                }
            }
        }

        private void ClearAppLevelProperties()
        {
            App.SelectedCharges = null;
            App.CurrentExpenseReport = null;
            App.CurrentExpenseItems = null;
        }

        void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
        {
            var request = args.Request;
            request.Data.Properties.Title = string.Format("{0} - {1}",
                expenseReport.EmployeeName, expenseReport.Purpose);
            request.Data.Properties.Description = string.Format(
                "Please review expense report {0}", expenseReport.ReportNumber);

            var builder = new StringBuilder();
            builder.Append("\r\n");
            builder.Append("This report contains the following:\r\n");
            foreach (ExpenseItemViewModel item in expenseItems)
            {
                builder.Append(string.Format("    - {0} on {1:d} for {2:C}",
                    item.Description, item.ExpenseDate, item.BilledAmount));
                builder.Append("\r\n\r\n");
            }
            request.Data.SetText(builder.ToString());
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            dataTransferManager.DataRequested -= new TypedEventHandler<
                DataTransferManager, DataRequestedEventArgs>(OnDataRequested);
            App.LastPage = "ExpenseReportPage";
        }

    }
}
